package com.lzc.blog.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.lzc.blog.dao.dos.Archives;
import com.lzc.blog.dao.mapper.ArticleBodyMapper;
import com.lzc.blog.dao.mapper.ArticleTagMapper;
import com.lzc.blog.dao.mapper.CommentMapper;
import com.lzc.blog.dao.pojo.*;
import com.lzc.blog.service.*;
import com.lzc.blog.utils.QiniuUtils;
import com.lzc.blog.utils.UserThreadLocal;
import com.lzc.blog.vo.ArticleBodyVo;
import com.lzc.blog.vo.ArticleVo;
import com.lzc.blog.vo.Result;
import com.lzc.blog.vo.TagVo;
import com.lzc.blog.vo.params.ArticleBodyParam;
import com.lzc.blog.vo.params.ArticleParam;
import com.lzc.blog.vo.params.PageParams;
import com.lzc.blog.dao.mapper.ArticleMapper;
import org.joda.time.DateTime;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class ArticleServiceImpl implements ArticleService {

    @Autowired
    private CommentMapper commentMapper;

    @Autowired
    private ArticleMapper mapper;

    @Autowired
    private TagService tagService;

    @Autowired
    private SysUserService sysUserService;

    @Autowired
    private CategoryService categoryService;

    @Autowired
    private ArticleTagMapper articleTagMapper;

    @Override
    public Result listArticle(PageParams pageParams) {
        Page<Article> page=new Page<Article>(pageParams.getPage(),pageParams.getPageSize());
      IPage<Article> articleIPage=  mapper.listArticle(page,
                pageParams.getCategoryId(),
                pageParams.getTagId(),
                pageParams.getYear(),
                pageParams.getMonth());

      List<Article> records=articleIPage.getRecords();
        return Result.success(copyList(records,true,true));
    }

    /**
     * 1.分页查询article数据库表
     * @param pageParams
     * @return
     */
 /*   @Override
    public Result listArticle(PageParams pageParams) {
        IPage<Article> page=new Page<Article>(pageParams.getPage(),pageParams.getPageSize());
        LambdaQueryWrapper<Article> wrapper=new LambdaQueryWrapper<>();
        //如果参数传了分类id，则添加条件，根据分类id查文章
        if (pageParams.getCategoryId()!=null){
            wrapper.eq(Article::getCategoryId,pageParams.getCategoryId());
        }
        List<Long> list=new ArrayList<>();
        if (pageParams.getTagId()!=null){
            //加入标签 条件查询
            //article表中并没有tagId 先根据tagId查Article_Tag表，查出articleId,再根据articleId查
            LambdaQueryWrapper<ArticleTag> queryWrapper=new LambdaQueryWrapper<>();
            queryWrapper.eq(ArticleTag::getTagId,pageParams.getTagId());
            queryWrapper.select(ArticleTag::getArticleId);
            List<ArticleTag> articleIds= this.articleTagMapper.selectList(queryWrapper);
            for (ArticleTag articleId : articleIds) {
                list.add(articleId.getArticleId());
            }
            if (list.size()>0){
                // and id in ()
                wrapper.in(Article::getId,list);
            }

        }
        //条件：置顶排序, 根据创建时间倒序排列
        wrapper.orderByDesc(Article::getWeight,Article::getCreateDate);
        IPage<Article> articlePage = mapper.selectPage(page, wrapper);
        List<Article> records = articlePage.getRecords();
        List<ArticleVo> articleVoList=copyList(records,true,true);
        return Result.success(articleVoList);
    }*/




    /**
     * 首页，查询最热文章
     * @param limit
     * @return
     */
    @Override
    public Result hotArticle(int limit) {
        LambdaQueryWrapper<Article> queryWrapper=new LambdaQueryWrapper<>();
        queryWrapper.orderByDesc(Article::getViewCounts);
        queryWrapper.last("limit "+limit);
        queryWrapper.select(Article::getId,Article::getTitle);
        List<Article> list = mapper.selectList(queryWrapper);
        return Result.success(copyList(list,false,false));
    }

    /**
     * 最新文章
     * @param limit
     * @return
     */
    @Override
    public Result newArticle(int limit) {
        LambdaQueryWrapper<Article> queryWrapper=new LambdaQueryWrapper<>();
        queryWrapper.orderByDesc(Article::getCreateDate);
        queryWrapper.last("limit "+limit);
        queryWrapper.select(Article::getId,Article::getTitle);
        List<Article> list = mapper.selectList(queryWrapper);
        return Result.success(copyList(list,false,false));
    }

    /**
     * 文章归档
     * @return
     */
    @Override
    public Result listArchives() {
        List<Archives> archives= mapper.listArchives();

        return Result.success(archives);
    }

    @Autowired
    private ThreadService threadService;

    @Override
    public Result findArticleById(Long articleId) {
        /**
         * 1.根据id查询文章信息
         * 2.根据bodyid与categoryId 去做关联
         *
         */

        Article article = this.mapper.selectById(articleId);

        ArticleVo articleVo = copy(article, true, true,true,true);
        articleVo.setAuthorId(String.valueOf(article.getAuthorId()));
        //查看完文章之后，本应该直接返回数据，
        //这时候做了一个更新操作，更新时加写锁，阻塞其他的读操作，性能就会比较低
        //更新 增加了此接口的 耗时 如果一旦更新出问题，不能影响 查看文章的操作
        //线程池  可以把更新操作扔到线程池中去执行，这样就不会影响到主线程
        threadService.updateArticleViewCount(mapper,article);

        return Result.success(articleVo);
    }
    /**
     * 文章内容详情
     * @param bodyId
     * @return
     */
    @Autowired
    private ArticleBodyMapper articleBodyMapper;
    private ArticleBodyVo findArticleBodyById(Long bodyId) {
        ArticleBody articleBody = articleBodyMapper.selectById(bodyId);
        ArticleBodyVo articleBodyVo=new ArticleBodyVo();
        articleBodyVo.setContent(articleBody.getContent());
        return articleBodyVo;
    }


    /**
     * 发布文章
     * @param articleParam
     * @return
     */
    @Override

    public Result publish(ArticleParam articleParam) {
        //能拿到用户的前提是，拦截器必须拦截这个接口
        SysUser user = UserThreadLocal.get();
        /*
         * 1.发布文章 构建Article对象
         * 2.作者id 当前用户
         * 3.标签 要将标签加入到关联列表当中
         * 4.body 内容存储
         */

        Article article=new Article();
        article.setAuthorId(user.getId());
        article.setWeight(Article.Article_Common);
        article.setViewCounts(0);
        article.setTitle(articleParam.getTitle());
        article.setCommentCounts(0);
        article.setSummary(articleParam.getSummary());
        article.setCategoryId(Long.parseLong(articleParam.getCategory().getId()));
        article.setCreateDate(System.currentTimeMillis());
        if (articleParam.getId()!=null){
            article.setId(articleParam.getId());
            //查询原文章
            Article havingArticle = this.mapper.selectById(articleParam.getId());
            System.out.println("articlr=>"+havingArticle);
            if (havingArticle!=null){
                //如果文章存在，则修改文章
                this.mapper.updateById(article);

                // 修改 tag （先删再存）
                LambdaQueryWrapper<ArticleTag> queryWrapper1 = new LambdaQueryWrapper();
                queryWrapper1.eq(ArticleTag::getArticleId,havingArticle.getId());
                articleTagMapper.delete(queryWrapper1);
                List<TagVo> tags=articleParam.getTags();
                if (tags!=null){
                    for (TagVo tag : tags) {
                        ArticleTag articleTag=new ArticleTag();
                        Long articleId=article.getId();
                        articleTag.setArticleId(articleId);
                        articleTag.setTagId(Long.parseLong(tag.getId()));
                        this.articleTagMapper.insert(articleTag);
                    }
                }
                //修改   articlebody
                ArticleBodyParam body = articleParam.getBody();
                ArticleBody articleBody = new ArticleBody();
                LambdaQueryWrapper<ArticleBody> queryWrapper = new LambdaQueryWrapper<>();
                queryWrapper.eq(ArticleBody::getArticleId,articleParam.getId());
                ArticleBody articleBody1 = articleBodyMapper.selectOne(queryWrapper);
                articleBody.setId(articleBody1.getId());
                articleBody.setArticleId(articleParam.getId());
                articleBody.setContent(body.getContent());
                articleBody.setContentHtml(body.getContentHtml());
                articleBodyMapper.updateById(articleBody);

                Map<String, String> map =new HashMap<>();
                map.put("id",article.getId().toString());
                return Result.success(map);
            }
        }

        //需要先插入文章才能获取文章id
        this.mapper.insert(article);

        // 存 tag
        List<TagVo> tags=articleParam.getTags();
        if (tags!=null){
            for (TagVo tag : tags) {
                ArticleTag articleTag=new ArticleTag();
                Long articleId=article.getId();
                articleTag.setArticleId(articleId);
                articleTag.setTagId(Long.parseLong(tag.getId()));
                this.articleTagMapper.insert(articleTag);
            }
        }
        //存   articlebody
        ArticleBodyParam body = articleParam.getBody();
        ArticleBody articleBody = new ArticleBody();
        articleBody.setArticleId(article.getId());
        articleBody.setContent(body.getContent());
        articleBody.setContentHtml(body.getContentHtml());
        articleBodyMapper.insert(articleBody);

        //最开始，因为没有bodyId，所以现在要更新一次
        article.setBodyId(articleBody.getId());
        mapper.updateById(article);

        Map<String, String> map =new HashMap<>();
        map.put("id",article.getId().toString());
        return Result.success(map);
    }

    /**
     * 根据id删除文章
     * @param articleId
     * @return
     */
    @Override
    @Transactional
    public Result deleteById(Long articleId) {
        /**
         * 1.先根据关联表删外键 articlebody articletag comment
         * 2.再删文章
         */
        LambdaQueryWrapper<ArticleTag> queryWrapper1 = new LambdaQueryWrapper<>();
        queryWrapper1.eq(ArticleTag::getArticleId,articleId);
        this.articleTagMapper.delete(queryWrapper1);

        LambdaQueryWrapper<ArticleBody> queryWrapper2=new LambdaQueryWrapper<>();
        queryWrapper2.eq(ArticleBody::getArticleId,articleId);
        this.articleBodyMapper.delete(queryWrapper2);

        LambdaQueryWrapper<Comment> queryWrapper3 = new LambdaQueryWrapper<>();
        queryWrapper3.eq(Comment::getArticleId,articleId);
        this.commentMapper.delete(queryWrapper3);

        int i = this.mapper.deleteById(articleId);
        if (i==0){
           return Result.fail(1000001,"删除失败");
        }

        return Result.success("删除成功");



    }

    private List<ArticleVo> copyList(List<Article> records, boolean isTag, boolean isAuthor) {
        List<ArticleVo> articleVoList=new ArrayList<>();
        for (Article record : records) {
            articleVoList.add(copy(record,isTag,isAuthor,false,false));
        }
        return articleVoList;
    }

    private List<ArticleVo> copyList(List<Article> records, boolean isTag, boolean isAuthor,boolean isBody,boolean isCategory) {
        List<ArticleVo> articleVoList=new ArrayList<>();
        for (Article record : records) {
            articleVoList.add(copy(record,isTag,isAuthor,isBody,isCategory));
        }
        return articleVoList;
    }



    private ArticleVo copy(Article article,boolean isTag,boolean isAuthor,boolean isBody,boolean isCategory){
        ArticleVo articleVo=new ArticleVo();
        //复制相同属性
        BeanUtils.copyProperties(article,articleVo);
        articleVo.setId(String.valueOf(article.getId()));
        //时间类型不一致，需要通过主动设置来复制
        articleVo.setCreateDate(new DateTime(article.getCreateDate()).toString("yyyy-MM-dd HH:mm"));
        //并不是所有的接口 都需要标签，作者信息
        if(isTag){
            Long id = article.getId();
            articleVo.setTags(tagService.findTagsByArticleId(id));
        }
        if (isAuthor){
            long id=article.getAuthorId();
            articleVo.setAuthor(sysUserService.findUserById(id).getNickname());
        }
        if (isBody){
            Long bodyId=article.getBodyId();
            articleVo.setBody(findArticleBodyById(bodyId));
        }
        if (isCategory){
            Long categoryId=article.getCategoryId();
            articleVo.setCategory(categoryService.findCategoryById(categoryId));
        }

        return articleVo;
    }
}
